home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir39 / borfix.zip / BUFFERS.PAS next >
Pascal/Delphi Source File  |  1989-12-09  |  15KB  |  580 lines

  1. Unit Buffers;
  2.  
  3. InterFace
  4. {*********************************************************************}
  5. {****              Written 1989 by Rolf Ernst                     ****}
  6. {****                                                             ****}
  7. {****  Code requires Turbo Professional for the expanded memory   ****}
  8. {****  access. The procedures used should not take more than a    ****}
  9. {****  few lines to reproduce though.                             ****}
  10. {****                                                             ****}
  11. {****  This code is hereby in the public domain.                  ****}
  12. {*********************************************************************}
  13.  
  14. Uses Dos, TpEms;
  15.  
  16. Type
  17.   PtrRec = Record
  18.     Ofs, Seg : Word;
  19.   end;
  20.  
  21.   BigBlock = Array[0..1] Of Byte;
  22.   BigBlockPtr = ^BigBlock;
  23.   BufferPtr = ^BufferDesc;
  24.   BufferDesc = object
  25.     BufferAddr : BigBlockPtr;
  26.     EmsHandle  : Word;
  27.     InEms      : Boolean;
  28.     Size       : Word;
  29.     Next       : Pointer;
  30.     Constructor Init(BufferSize : Word; UseEms : Boolean);
  31.     Function    Map(Offset, Length : Word) : BigBlockPtr; Virtual;
  32.     Destructor  Done;
  33.   end;
  34.  
  35.   FileBufferPtr = ^FileBufferDesc;
  36.   FileBufferDesc = Object(BufferDesc)
  37.     PosBuffer   : LongInt;
  38.     BytesUsed   : Word;
  39.     Initialized : Boolean;
  40.     Modified    : Boolean;
  41.     Constructor Init(BufferSize : Word; UseEms : Boolean);
  42.   end;
  43.  
  44.   BufferChain = object
  45.     NumberOfBuffers, BlockSize:Word;
  46.     BufferHead, BufferTail : FileBufferPtr;
  47.     Procedure Init(BufSize, BufNum : Word; UseEms : Boolean);
  48.     Procedure ChainAtEnd(VAR B : FileBufferPtr);
  49.     Function  BuffersUnUsed:Word;
  50.     Procedure Done;
  51.   end;
  52.  
  53.   BufferFile=Object
  54.     F              : File;
  55.     FSize          : LongInt;
  56.     CurrentPos     : LongInt;
  57.     RecordSize     : Word;
  58.     BlockSize      : Word;
  59.     BufferS        : BufferChain;
  60.     FlushAll       : Boolean;
  61.     ReadAll        : Boolean;
  62.     NoBufferReads  : Boolean;
  63.     NoBufferWrites : Boolean;
  64.     NoBufferIng    : Boolean;
  65.  
  66.     Procedure Init(BufSize, BufNum:Word; UseEms : Boolean);
  67.               {Initialize BufNum buffers for the file, each being
  68.                Bufsize bytes big - use Expanded memory if UseEms is TRUE}
  69.  
  70.     Procedure Flush;
  71.               {Write all modified buffers to disk - does not cause DOS to
  72.                flush its buffers}
  73.  
  74.     Function  FreeBuffer : FileBufferPtr;
  75.               {Find an available Buffer - Flush a buffer if necessary}
  76.  
  77.     Procedure Read(VAR A; NumRecs : Word);
  78.               {Read a record buffered}
  79.  
  80.     Procedure DisableOutBound;
  81.               {Disable buffering when writing to a file}
  82.  
  83.     Procedure Write(VAR A; NumRecs : Word);
  84.               {Write a record buffered}
  85.  
  86.     Function  Eof:Boolean;
  87.               {Return true if the current position in the file is at its end}
  88.  
  89.     Procedure Seek(NewPos : LongInt);
  90.               {Go to a new position in the file}
  91.  
  92.     Function  FileSize:LongInt;
  93.               {Returns the size of a buffered file taking any data in the
  94.                buffers into consideration}
  95.  
  96.     Procedure Assign(Name : PathStr);
  97.               {Assign a name to a buffered file}
  98.  
  99.     Function  FilePos:LongInt;
  100.               {Returns the current position in a buffered file}
  101.  
  102.     Procedure Rewrite(RecSize : Word);
  103.               {Create a new file or overwrite an existing one}
  104.  
  105.     Procedure Reset(RecSize:Word);
  106.               {Open an existing file}
  107.  
  108.     Procedure SetWriteBias;
  109.               {Indicate, that the majority of the file operations will be
  110.                sequential writes - when a buffer needs to be flushed ALL
  111.                buffers will be flushed}
  112.  
  113.     Procedure SetReadBias;
  114.               {Indicate, that the majority of the file operations will be
  115.                sequential reads - when a buffer needs to be read ALL buffers
  116.                will be read from disk}
  117.  
  118.     Procedure ResetBias;
  119.               {Reset file access characteristics to its default values}
  120.  
  121.     Procedure DisableInBound;
  122.               {Disable buffering when reading from a dataset}
  123.  
  124.     Procedure EnableInBound;
  125.               {Enable buffering when reading from a dataset}
  126.  
  127.     Procedure EnableOutBound;
  128.               {Enable buffering when writing to a dataset}
  129.  
  130.     Procedure Done;
  131.               {Close the file and free all buffers}
  132.  
  133.   end;
  134.  
  135.  
  136. Implementation
  137.  
  138.  
  139.  
  140. Procedure EmsError;
  141. begin
  142.   Writeln('Severe Error in EMS handler');
  143.   readln;
  144.   halt;
  145. end;
  146.  
  147. Function MemToEms(BytesIn : LongInt) : Word;
  148. begin
  149.   MemToEms:=(BytesIn+16383) shr 14;
  150. end;
  151.  
  152. Procedure MapBuffer(Handle : Word; BytesInBuffer:Word);
  153. VAR
  154.   I : Word;
  155. begin
  156.   For I:=0 to Pred(MemToEms(BytesInBuffer)) do begin
  157.     If Not MapEmsPage(Handle,i,i) then EmsError;
  158.   end;
  159. end;
  160.  
  161. Procedure BufferFile.SetWriteBias;
  162. begin
  163.   FlushAll:=True;
  164.   ReadAll:=False;
  165. end;
  166.  
  167. Procedure BufferFile.DisableInBound;
  168. begin
  169.   NoBufferReads:=True;
  170. end;
  171.  
  172. Procedure BufferFile.EnableInBound;
  173. begin
  174.   NoBufferReads:=false;
  175. end;
  176.  
  177. Procedure BufferFile.DisableOutBound;
  178. begin
  179.   Flush;
  180.   NoBufferWrites:=True;
  181. end;
  182.  
  183. Procedure BufferFile.EnableOutBound;
  184. begin
  185.   NoBufferWrites:=False;
  186. end;
  187.  
  188. Procedure BufferFile.ResetBias;
  189. begin
  190.   FlushAll:=False;
  191.   ReadAll:=False;
  192.   NoBufferReads:=False;
  193.   NoBufferWrites:=False;
  194. end;
  195.  
  196. Procedure BufferFile.SetReadBias;
  197. begin
  198.   FlushAll:=False;
  199.   ReadAll:=True;
  200. end;
  201.  
  202.  
  203. Constructor BufferDesc.Init(BufferSize : Word; UseEms : Boolean);
  204. begin
  205.   InEms:=UseEms and EmsInstalled and
  206.     (EmsPagesAvail>=MemToEms(Buffersize));
  207.   Size:=BufferSize;
  208.   If InEms then begin
  209.     EmsHandle:=AllocateEMSPages(MemToEms(Size));
  210.     If EmsHandle=EmsErrorCode then EmsError;
  211.     BufferAddr:=EmsPageFramePtr;
  212.   end else GetMem(BufferAddr,Size);
  213.   Next:=Nil;
  214. end;
  215.  
  216. Function BufferDesc.Map(Offset, Length : Word) : BigBlockPtr;
  217. VAR
  218.   HighOffset : Word;
  219.   MyPointer  : BigBlockPTr;
  220. begin
  221.   MyPointer:=BufferAddr;
  222.   Inc(PtrRec(MyPointer).Ofs,Offset);
  223.   Map:=MyPointer;
  224.   If InEms then begin
  225.     HighOffset:=Pred(Offset+Length);
  226.     Offset:=Offset Shr 14;
  227.     HighOffset:=HighOffset shr 14;
  228.     repeat
  229.       If Not MapEmsPage(EMSHandle,Offset,Offset) then EmsError;
  230.       INC(Offset);
  231.     until Offset>HighOffset;
  232.   end;
  233. end;
  234.  
  235. Destructor BufferDesc.Done;
  236. begin
  237.   IF InEms then begin
  238.     If Not DeallocateEmsHandle(Emshandle) then EmsError;
  239.   end else FreeMem(BufferAddr,Size);
  240. end;
  241.  
  242. Constructor FileBufferDesc.Init(BufferSize : Word; UseEms : Boolean);
  243. begin
  244.   BufferDesc.Init(BufferSize, UseEms);
  245.   Initialized:=False;
  246.   Modified:=False;
  247. end;
  248.  
  249. Procedure BufferChain.Init(BufSize, BufNum : Word; UseEms : Boolean);
  250. VAR
  251.   I : Word;
  252. begin
  253.   NumberOfBuffers:=BufNum;
  254.   BufferTail:=Nil;
  255.   For i:=1 to BufNum do begin
  256.     New(BufferHead,Init(BufSize,UseEms));
  257.     BufferHead^.Next:=BufferTail;
  258.     BufferTail:=BufferHead;
  259.   end;
  260.   While BufferTail^.Next<>Nil do BufferTail:=BufferTail^.Next;
  261. end;
  262.  
  263. Procedure BufferChain.ChainAtEnd(VAR B : FileBufferPtr);
  264. VAR
  265.   BufPtr:FileBufferPtr;
  266. begin
  267.   If (NumberOfBuffers>1) and (B<>BufferTail) then begin
  268.     BufferTail^.Next:=B;
  269.     BufferTail:=B;
  270.     If B=BufferHead then begin
  271.       BufferHead:=B^.Next;
  272.       B^.Next:=Nil;
  273.     end else begin
  274.       Bufptr:=BufferHead;
  275.       While BufPtr^.Next<>B do Bufptr:=BufPtr^.Next;
  276.       BufPtr^.Next:=B^.Next;
  277.       B^.Next:=Nil;
  278.     end;
  279.   end;
  280. end;
  281.  
  282.  
  283. Procedure BufferFile.Init(BufSize, BufNum:Word; UseEms : Boolean);
  284. VAR
  285.   I : Word;
  286. begin
  287.   If (BufSize=0) or (BufNum=0) then begin
  288.     NoBufferIng:=True;
  289.     exit;
  290.   end;
  291.   UseEms:=UseEms and EmsInstalled and
  292.     (EmsPagesAvail>=BufNum * MemToEms(Bufsize));
  293.   Buffers.Init(BufSize, BufNum, USeEms);
  294.   FlushAll:=False;
  295.   ReadAll:=False;
  296.   NoBufferReads:=False;
  297.   NoBufferWrites:=False;
  298.   NoBuffering:=False;
  299.   BlockSize:=BufSize;
  300. end;
  301.  
  302. Function BufferFile.FreeBuffer:FileBufferPtr;
  303. VAR
  304.   BufPtr,SavePtr : FileBufferPtr;
  305.   LowPos : LongInt;
  306.   MyPointer : Pointer;
  307. begin
  308.   BufPtr:=Buffers.BufferHead;
  309.   LowPos:=$7fffffff;
  310.   While BufPtr<>Nil do begin
  311.     With BufPtr^ do begin
  312.       If (Not Modified) or (Not initialized) then begin
  313.         FreeBuffer:=BufPtr;
  314.         Modified:=False;
  315.         FreeBuffer:=BufPtr;
  316.         Buffers.ChainAtEnd(BufPtr);
  317.         Exit;
  318.       end;
  319.       If PosBuffer<LowPos then begin
  320.         LowPos:=PosBuffer;
  321.         SavePtr:=BufPtr;
  322.       end;
  323.       BufPtr:=Next;
  324.     end;
  325.   end;
  326.   If FlushAll then begin
  327.     Flush;
  328.     FreeBuffer:=Buffers.BufferHead;
  329.   end;
  330.   With SavePtr^ do begin
  331.     System.Seek(F,PosBuffer);
  332.     MyPointer:=Map(0,BytesUsed);
  333.     BlockWrite(F,MyPointer^,BytesUsed);
  334.     BytesUsed:=0;
  335.     Modified:=False;
  336.   end;
  337.   FreeBuffer:=SavePtr;
  338.   Buffers.ChainAtEnd(SavePtr);
  339. end;
  340.  
  341. Procedure BufferFile.Flush;
  342. VAR
  343.   BufPtr : FileBufferPtr;
  344.   MyPointer : Pointer;
  345. begin
  346.   If NoBuffering then exit;
  347.   BufPtr:=Buffers.BufferHead;
  348.   While BufPtr<>Nil do begin
  349.     With BufPTr^ do begin
  350.       If Modified then begin
  351.         System.Seek(F,PosBuffer);
  352.         MyPointer:=Map(0,BytesUsed);
  353.         BlockWrite(F,BufferAddr^,BytesUsed);
  354.         Modified:=False;
  355.       end;
  356.       BufPtr:=Next;
  357.     end;
  358.   end;
  359. end;
  360.  
  361. Function  BufferCHain.BuffersUnUsed:Word;
  362. VAR
  363.   BufPtr : FileBufferPtr;
  364.   Count : Word;
  365. begin
  366.   Count:=0;
  367.   BufPtr:=BufferHead;
  368.   While BufPtr<>Nil do begin
  369.     With BufPtr^ do begin
  370.       If (Not Initialized) or (Not Modified) then Inc(Count);
  371.       BufPtr:=Next;
  372.     end;
  373.   end;
  374.   BuffersUnUsed:=Count;
  375. end;
  376.  
  377. Function BufferFile.FileSize:LongInt;
  378. begin
  379.   If NoBuffering then FileSize:=System.FIleSize(F) else
  380.     FileSize:=Fsize div RecordSize;
  381. end;
  382.  
  383. Function BufferFile.FilePos:LongInt;
  384. begin
  385.   If NoBuffering then FilePos:=System.FilePos(F) else
  386.     FilePos:=CurrentPos div RecordSize;
  387. end;
  388.  
  389. Procedure BufferFile.Read(VAR A; NumRecs : Word);
  390. VAR
  391.   I,J    : Word;
  392.   BufPtr   :  FileBufferPtr;
  393.   TargetPtr : BigBlockPtr;
  394.   More  : Boolean;
  395.   BaseBufferToGet : LongInt;
  396.   MyPointer : Pointer;
  397. begin
  398.   If NoBuffering then BlockRead(F,A,NuMRecs) else begin
  399.     NumRecs:=NumRecs*RecordSize;
  400.     TargetPtr:=@A;
  401.     Repeat
  402.       BaseBufferToGet:=CurrentPos-(CurrentPos Mod BlockSize);
  403.       BufPtr:=Buffers.BufferHead;
  404.       More:=True;
  405.       While (BufPtr<>Nil) and More Do begin
  406.         With BufPtr^ do begin
  407.           If (PosBuffer=BaseBufferToGet) and Initialized then more:=False else
  408.           BufPtr:=Next;
  409.         end;
  410.       end;
  411.       If BufPtr=Nil then begin
  412.         If NoBufferReads then begin
  413.           System.Seek(F,CurrentPos);
  414.           BlockRead(F,TargetPtr^,NumRecs);
  415.           Inc(CurrentPos,NumRecs);
  416.           exit;
  417.         end;
  418.         BufPtr:=FreeBuffer;
  419.         With BufPtr^ do begin
  420.           System.Seek(F,BaseBufferToGet);
  421.           PosBuffer:=BaseBufferToGet;
  422.           MyPointer:=Map(0,BlockSize);
  423.           BlockRead(F,MyPointer^,BlockSize,BytesUsed);
  424.           Initialized:=True;
  425.         end;
  426.         If ReadAll then begin
  427.           J:=Buffers.BuffersUnUsed;
  428.           If J>0 then Dec(j);
  429.           I:=1;
  430.           While (I<= J) and (BufPtr^.BytesUsed=BlockSize) do begin
  431.             Inc(BaseBufferToGet,BlockSize);
  432.             BufPtr:=FreeBuffer;
  433.             With BufPtr^ do begin
  434.               PosBuffer:=BaseBufferToGet;
  435.               MyPointer:=Map(0,BlockSize);
  436.               BlockRead(F,MyPointer^,BlockSize,BytesUsed);
  437.               Initialized:=True;
  438.             end;
  439.             Inc(I);
  440.           end;
  441.         end;
  442.       end else begin
  443.         With BufPtr^ do begin
  444.           J:=CurrentPos-PosBuffer;
  445.           I:=BytesUsed-j;
  446.           If I>NumRecs then I:=NumRecs;
  447.           MyPointer:=Map(J,I);
  448.           Move(MyPointer^,TargetPtr^,I);
  449.           Inc(CurrentPos,I);
  450.           Dec(NumRecs,I);
  451.           Inc(PtrRec(TargetPtr).Ofs,I);
  452.         end;
  453.       end;
  454.     until NumRecs=0;
  455.   end;
  456. end;
  457.  
  458. Procedure BufferFile.Write(VAR A; NumRecs : Word);
  459. VAR
  460.   I,J : WOrd;
  461.   BufPtr : FileBufferPtr;
  462.   TargetPTr,MyPointer : Pointer;
  463.   BaseBufferToGet : LongInt;
  464.   BytesNeeded : LongInt;
  465.   OK,More : Boolean;
  466. begin
  467.   If NoBuffering then BlockWrite(F,A,NumRecs) else begin
  468.     TargetPtr:=@A;
  469.     NumRecs:=NumRecs*RecordSize;
  470.     Repeat
  471.       BaseBufferToGet:=CUrrentPos-(CurrentPos Mod BlockSize);
  472.       BufPtr:=Buffers.BufferHead;
  473.       More:=True;
  474.       While (BufPtr<>Nil) and More Do begin
  475.         With BufPtr^ do begin
  476.           If (Initialized) and (BaseBufferToGet=PosBuffer) then begin
  477.             BytesNeeded:=CurrentPos-PosBuffer+NumRecs;
  478.             If BytesNeeded>BytesUsed then begin
  479.               If BytesNeeded>BlockSize then BytesUsed:=BlockSize else
  480.               BytesUsed:=BytesNeeded;
  481.               Fsize:=BaseBufferToGet+BytesUsed;
  482.             end;
  483.             More:=False;
  484.           end else BufPtr:=Next;
  485.         end;
  486.       end;
  487.       If BufPtr=Nil then begin
  488.         If NoBufferWrites then begin
  489.           If BaseBufferToGet<>CurrentPos then begin
  490.             System.Seek(F,CurrentPos);
  491.             BlockWrite(F,A,NumRecs);
  492.             Inc(CurrentPos,NumRecs);
  493.             exit;
  494.           end;
  495.         end;
  496.         BufPtr:=FreeBuffer;
  497.         With BufPtr^ do begin
  498.           System.Seek(F,BaseBufferToGet);
  499.           PosBuffer:=BaseBufferToGet;
  500.           If PosBuffer<SyStem.FileSize(F) then begin
  501.             MyPointer:=Map(0,BlockSize);
  502.             BlockRead(F,MyPointer^,BlockSize,BytesUsed);
  503.           end else BytesUsed:=0;
  504.           Initialized:=True;
  505.         end;
  506.       end else begin
  507.         With BufPtr^ do begin
  508.           J:=CurrentPos-PosBuffer;
  509.           I:=BytesUsed-j;
  510.           If I>NumRecs then I:=NumRecs;
  511.           MyPointer:=Map(J,I);
  512.           Move(TargetPtr^,MyPointer^,I);
  513.           Modified:=True;
  514.           Inc(CurrentPos,I);
  515.           Dec(NumRecs,I);
  516.           Inc(PtrRec(TargetPtr).Ofs,I);
  517.         end;
  518.       end;
  519.     until NumRecs=0;
  520.   end;
  521. end;
  522.  
  523. Function BufferFile.Eof:Boolean;
  524. begin
  525.   If NoBuffering then Eof:=System.Eof(F) else
  526.     Eof:=CurrentPos=Fsize;
  527. end;
  528.  
  529. Procedure BufferFile.Seek(NewPos : LongInt);
  530. begin
  531.   If NoBuffering then System.Seek(F,Newpos) else
  532.     CurrentPos:=NewPos*RecordSize;
  533. end;
  534.  
  535. Procedure BufferFile.Assign(Name : PathStr);
  536. begin
  537.   System.Assign(F,Name);
  538. end;
  539.  
  540. Procedure BufferFile.Rewrite(RecSize:Word);
  541. begin
  542.   RecordSize:=RecSize;
  543.   If Not NoBuffering then Recsize:=1;
  544.   System.Rewrite(F,RecSize);
  545.   Fsize:=0;
  546.   CurrentPos:=0;
  547. end;
  548.  
  549. Procedure BufferFile.Reset(RecSize : Word);
  550. begin
  551.   RecordSize:=RecSize;
  552.   If Not NoBuffering then RecSize:=1;
  553.   System.Reset(F,RecSize);
  554.   Fsize:=System.FileSize(F);
  555.   CurrentPos:=0;
  556. end;
  557.  
  558. Procedure BufferChain.Done;
  559. begin
  560.   repeat
  561.     with BufferHead^ do begin
  562.       BufferTail:=BufferHead^.Next;
  563.       Dispose(BufferHead,Done);
  564.       BufferHead:=BufferTail;
  565.     end;
  566.   until Bufferhead=Nil;
  567. end;
  568.  
  569. Procedure BufferFile.Done;
  570. VAR
  571.   BufferTail : BufferPtr;
  572.   Ok : Boolean;
  573. begin
  574.   Flush;
  575.   Close(F);
  576.   If Not NoBuffering then Buffers.Done;
  577. end;
  578. end.
  579.  
  580.